package cn.sc.summer.core.annotation;

import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.sc.summer.exception.exceptions.CommonException;
import lombok.extern.slf4j.Slf4j;

import javax.validation.Constraint;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import javax.validation.Payload;
import java.lang.annotation.*;

/**
 * 枚举校验类注解
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = {EnumValid.EnumValidAspect.class})
@Documented
public @interface EnumValid {

    /**
     * 校验错误信息
     */
    String message() default "不存在对应的枚举类信息!";

    /**
     * 校验分组信息
     */
    Class<?>[] groups() default {};

    /**
     * 载荷
     */
    Class<? extends Payload>[] payload() default {};

    /**
     * 需要校验的枚举类
     */
    Class<? extends Enum<?>> target();

    /**
     * 需要校验的字段
     */
    String arg() default "Type";

    /**
     * 配合注解 @EnumValid验证每个枚举值是否符合枚举类的工具类
     */
    @Slf4j
    class EnumValidAspect implements ConstraintValidator<EnumValid, Object> {

        private EnumValid enumValid;

        @Override
        public void initialize(EnumValid enumValid) {
            this.enumValid = enumValid;
        }

        @Override
        public boolean isValid(Object value, ConstraintValidatorContext context) {
            if (ObjectUtil.isNull(value)) {
                return true;
            }
            Class<? extends Enum<?>> cls = enumValid.target();
            String arg = enumValid.arg();
            Object[] objects = cls.getEnumConstants();
            for (Object obj : objects) {
                try {
                    Object getArg = obj.getClass().getMethod("get" + CharSequenceUtil.upperFirst(arg)).invoke(obj);
                    if (ObjectUtil.equals(value, getArg)) {
                        return true;
                    }
                } catch (NoSuchMethodException | SecurityException noSuchMethodException) {
                    noSuchMethodException.printStackTrace();
                    return false;
                } catch (Exception e) {
                    e.printStackTrace();
                    throw new CommonException(enumValid.message(), e);
                }
            }
            return false;
        }

    }

}
